
/**
* @module bosh
* @author: Hjava
* @description: 长轮询模块
* @since: 2018-07-15 21:12:23
*/
Object.defineProperty(exports, "__esModule", { value: true });
var base64_1 = __webpack_require__(/*! _util/base64 */ "./src/core/utils/base64.ts");
var isIE_1 = __webpack_require__(/*! _util/isIE */ "./src/core/utils/isIE.ts");
var analytics_1 = __webpack_require__(/*! _util/analytics */ "./src/core/utils/analytics.ts");
var uuid_1 = __webpack_require__(/*! _util/uuid */ "./src/core/utils/uuid.ts");
var userData_1 = __webpack_require__(/*! _util/userData */ "./src/core/utils/userData.ts");
var EventEmitter = __webpack_require__(/*! eventemitter3 */ "./node_modules/eventemitter3/index.js");
var log_1 = __webpack_require__(/*! ./../utils/log */ "./src/core/utils/log.ts");
var ERROR_INFO = {
    TIME_OUT: {
        code: 1,
        reason: 'timeout'
    },
    ABORT: {
        code: 2,
        reason: 'abort'
    },
    AUTH_FAIL: {
        code: 3,
        reason: 'auth fail'
    },
    SERVER_ERROR: {
        code: 4,
        reason: 'server error'
    },
    NETWORK_ERROR: {
        code: 5,
        reason: 'network error'
    }
};
var LongPolling = /** @class */ (function () {
    function LongPolling() {
        this._token = '';
        this._pollingXHR = null;
        this._eventEmitter = null;
        this._startTime = 0;
        this._startConnectFlag = true;
        this._retryHandle = null;
        this._retryTime = 0.5 * 1000;
        this.url = '';
        this.status = 'normal';
        this.sessionId = uuid_1.default.next();
        this._eventEmitter = new EventEmitter();
        this.status = 'normal';
    }
    LongPolling.prototype.connect = function (url) {
        this.url = url;
        this._token = '';
        this.status = 'normal';
        this._closePolling();
        this._pollingXHR = new XHR({
            url: this.url + '/polling',
            method: 'POST',
            reqType: 'open',
            onRequestStateChange: this._onRequestStateChange.bind(this),
            onError: this._XHRError.bind(this)
        });
        this._startConnectFlag = true;
        this._pollingXHR.reqType = 'open';
        this._pollingXHR.send('open=true');
        this._startTime = Date.now();
        var valObject = {
            host: this.url,
            net: navigator.onLine ? 1 : 0,
            websocketId: this.sessionId
        };
        log_1.default.log('LongPolling::connect info:' + JSON.stringify(valObject));
        analytics_1.default.report({
            nm: 'login_bosh_start',
            val: valObject
        });
    };
    LongPolling.prototype.disconnect = function () {
        this._closePolling();
        this.status = 'disconnect';
        var valObject = {
            websocketId: this.sessionId,
            net: navigator.onLine ? 1 : 0,
            host: this.url
        };
        log_1.default.log('LongPolling::disconnect info:' + JSON.stringify(valObject));
        analytics_1.default.report({
            nm: 'login_bosh_close',
            val: valObject
        });
    };
    LongPolling.prototype.send = function (data) {
        var sendReq = new XHR({
            'url': this.url + '/send',
            'method': 'POST',
            reqType: 'send',
            onRequestStateChange: this._onRequestStateChange.bind(this),
            onError: this._XHRError.bind(this)
        });
        sendReq.reqType = 'send';
        try {
            var sendBase64Str = base64_1.default.BAtob64(new Uint8Array(data));
            sendReq.send("token=" + this._token + "&base64Str=" + encodeURIComponent(sendBase64Str));
        }
        catch (e) {
            log_1.default.error(e);
        }
    };
    LongPolling.prototype.onOpen = function (func) {
        var _this = this;
        this._eventEmitter.on('open', function () {
            analytics_1.default.report({
                nm: 'login_bosh_success',
                val: {
                    time: Date.now() - _this._startTime
                }
            });
            log_1.default.log('LongPolling::onOpen id:' + _this.sessionId + (" \u5F53\u524D WebSocket \u5730\u5740: " + _this.url + "   \u5F53\u524D\u4F7F\u7528\u73AF\u5883:" + userData_1.default.get('env')));
            func();
        });
    };
    LongPolling.prototype.onMessage = function (func) {
        this._eventEmitter.on('message', function (message) {
            func(message);
        });
    };
    LongPolling.prototype.onClose = function (func) {
        var _this = this;
        this._eventEmitter.on('close', function () {
            var closeLog = 'LongPolling::onClose id:' + _this.sessionId + ' url:' + _this.url;
            log_1.default.log(closeLog);
            analytics_1.default.report({
                nm: 'login_bosh_error',
                val: {
                    net: navigator.onLine ? 1 : 0
                }
            });
            func(_this.sessionId);
        });
    };
    LongPolling.prototype.onError = function (func) {
        var _this = this;
        this._eventEmitter.on('error', function (error) {
            var errorLog = 'LongPolling::onError id:' + _this.sessionId + ' url:' + _this.url + 'info:' + error;
            log_1.default.log(errorLog);
            func(error);
            // websocket 'error' event will emit 'close' event, but we need not handle 'abort' error, need a timer because the `_closePolling` will invoke the onError callback, and will invoke `_closePolling` again
            // todo need to avoid invoke the function onError
            if (!_this._retryHandle) {
                _this._retryHandle = setTimeout(function () {
                    _this._eventEmitter.emit('close');
                    _this._retryHandle = null;
                }, _this._retryTime);
            }
        });
    };
    LongPolling.prototype._connectSuccess = function (res) {
        try {
            var resObj = JSON.parse(res);
            this._token = resObj.data.token;
            this._pollingXHR = null;
            this._polling();
        }
        catch (e) {
            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
        }
        log_1.default.log('LongPolling::_connectSuccess current polling url: ', this.url);
    };
    LongPolling.prototype._polling = function () {
        if (this.status == 'disconnect') {
            return;
        }
        this._closePolling();
        this._pollingXHR = new XHR({
            url: this.url + '/polling',
            method: 'POST',
            reqType: 'polling',
            onRequestStateChange: this._onRequestStateChange.bind(this),
            onError: this._XHRError.bind(this)
        });
        this._pollingXHR.reqType = 'polling';
        // when userData can get 'altoken', then the user is authSuccess
        if (!this._startConnectFlag && userData_1.default.get('uid')) {
            this._pollingXHR.send("token=" + this._token + "&open=false&ping=true&appId=" + userData_1.default.get('appId') + "&uid=" + userData_1.default.get('uid'));
        }
        else {
            this._pollingXHR.send("token=" + this._token + "&open=false");
            this._startConnectFlag = false;
        }
    };
    LongPolling.prototype._closePolling = function () {
        if (this._pollingXHR) {
            this._pollingXHR.close();
            this._pollingXHR = null;
        }
    };
    LongPolling.prototype._XHRError = function (res) {
        this._eventEmitter.emit('error', res);
    };
    LongPolling.prototype._onRequestStateChange = function (req) {
        var xhr = req.xhr;
        if (xhr.readyState === 4) {
            try {
                clearTimeout(req._timer);
                if (200 <= xhr.status && xhr.status <= 206) {
                    req.status = 'success';
                    switch (req.reqType) {
                        case 'open':
                            this._connectSuccess(xhr.responseText);
                            break;
                        case 'polling':
                            this._onMessage(xhr.responseText);
                            break;
                        case 'send':
                            break;
                    }
                }
                else {
                    req.status = 'error';
                    switch (req.reqType) {
                        case 'open':
                            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
                            break;
                        case 'polling':
                            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
                            break;
                        case 'send':
                            break;
                    }
                }
            }
            catch (e) {
                log_1.default.error(e);
            }
        }
    };
    LongPolling.prototype._onMessage = function (message) {
        var _this = this;
        var msgObj;
        try {
            msgObj = JSON.parse(message);
        }
        catch (e) {
            log_1.default.error(e);
            // 下面可能会进到同一个处理逻辑里面，但是在此处理代码更清晰
            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
        }
        if (msgObj && msgObj.code === 200) {
            if (msgObj.data && msgObj.data.length) {
                for (var i = 0, len = msgObj.data.length; i < len; i++) {
                    var dataItem = msgObj.data[i];
                    if (dataItem.content.code == 0) {
                        this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
                        //this._disconnect(); // may be
                    }
                    else if (dataItem.content.type == 'open') {
                        this._eventEmitter.emit('open');
                    }
                    else if (dataItem.content.type == 'transfer') {
                        //认为bosh已经和信令建立了连接
                        var base64str = dataItem.content.data.base64Str;
                        var msgBuffer = base64_1.default.b64toBA(base64str);
                        this._eventEmitter.emit('message', msgBuffer.buffer);
                    }
                }
            }
            this._pollingXHR = null;
            setTimeout(function () {
                _this._polling();
            }, 0);
        }
        else if (msgObj && msgObj.code !== void 0 && msgObj.code === 411) {
            // 应该disconnect
            this._eventEmitter.emit('error', ERROR_INFO.AUTH_FAIL);
        }
        else if (msgObj && msgObj.code !== void 0 && msgObj.code === 500) {
            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
        }
        else if (!msgObj) {
            this._eventEmitter.emit('error', ERROR_INFO.SERVER_ERROR);
        }
    };
    return LongPolling;
}());
exports.default = LongPolling;
var XHR = /** @class */ (function () {
    function XHR(_a) {
        var url = _a.url, _b = _a.method, method = _b === void 0 ? 'POST' : _b, _c = _a.contentType, contentType = _c === void 0 ? 'application/x-www-form-urlencoded' : _c, _d = _a.reqType, reqType = _d === void 0 ? 'send' : _d, _e = _a.timeout, timeout = _e === void 0 ? 40 * 1000 : _e, onRequestStateChange = _a.onRequestStateChange, onError = _a.onError;
        this._method = 'GET';
        this._contentType = 'application/x-www-form-urlencoded';
        this._timeout = 40 * 1000;
        this._reqType = ''; // open, polling, send
        this._timer = null;
        this.url = '';
        this.xhr = null;
        this.status = '';
        this.url = url;
        this._method = method;
        this._contentType = contentType;
        this._reqType = reqType;
        this._timeout = timeout;
        this._onError = onError;
        this.xhr = this.create(onRequestStateChange);
        // open, pending, abort, success, error
        this.status = '';
    }
    XHR.prototype.create = function (onRequestStateChange) {
        var _this = this;
        var xhr = new XMLHttpRequest();
        xhr.open(this._method, this.url, true);
        this.status = 'open';
        if (xhr.overrideMimeType) {
            xhr.overrideMimeType('text/plain');
        }
        xhr.onreadystatechange = function (e) {
            onRequestStateChange(_this);
        };
        xhr.onerror = function (e) {
            // 阻止cat捕获网络错误
            e.stopImmediatePropagation();
        };
        return xhr;
    };
    XHR.prototype.send = function (data) {
        var _this = this;
        this.xhr.setRequestHeader('Content-type', this._contentType);
        this.xhr.send(data);
        this.status = 'pending';
        if (this._timer) {
            clearTimeout(this._timer);
            this._timer = null;
        }
        this._timer = setTimeout(function () {
            _this._onError(ERROR_INFO.TIME_OUT);
        }, this._timeout);
    };
    XHR.prototype.close = function (onError) {
        if (!isIE_1.default) {
            //这里在IE9+下面可能有问题,参考http://stackoverflow.com/questions/7287706/ie-9-javascript-error-c00c023f
            this.xhr.abort();
        }
        this.status = 'abort';
        this._onError(ERROR_INFO.ABORT);
        clearTimeout(this._timer);
    };
    return XHR;
}());


//# sourceURL=webpack://MTDX/./src/core/login/longPolling.ts?